package serv_impl

import (
	"context"
	"sort"

	"atomgit.com/openlinksaas/easy_trace/config"
	"atomgit.com/openlinksaas/easy_trace/data_store"
	"atomgit.com/openlinksaas/proto-gen-go.git/trace_proxy_api"
	"go.opentelemetry.io/collector/pdata/pcommon"
)

type TraceProxyApiImpl struct {
	trace_proxy_api.UnimplementedTraceProxyApiServer
	dataStore *data_store.DataStore
	cfgPath   string
}

func NewTraceProxyApiImpl(dataStore *data_store.DataStore, cfgPath string) *TraceProxyApiImpl {
	return &TraceProxyApiImpl{
		dataStore: dataStore,
		cfgPath:   cfgPath,
	}
}

func (apiImpl *TraceProxyApiImpl) ListServiceName(ctx context.Context, req *trace_proxy_api.ListServiceNameRequest) (*trace_proxy_api.ListServiceNameResponse, error) {
	emptyList := []string{}

	cfg, err := config.LoadServerCfg(apiImpl.cfgPath)
	if err != nil {
		return nil, err
	}
	tokenInfo, err := apiImpl.getTokenInfo(cfg.LinkSaasAddr, req.Token)
	if err != nil {
		return &trace_proxy_api.ListServiceNameResponse{
			Code:            trace_proxy_api.ListServiceNameResponse_CODE_WRONG_TOKEN,
			ErrMsg:          "错误的访问令牌",
			ServiceNameList: emptyList,
		}, nil
	}
	if !apiImpl.hasPerm(tokenInfo.ProjectId, cfg.ProjectList) {
		return &trace_proxy_api.ListServiceNameResponse{
			Code:            trace_proxy_api.ListServiceNameResponse_CODE_NO_PERMISSION,
			ErrMsg:          "没有权限",
			ServiceNameList: emptyList,
		}, nil
	}

	serviceNameList := apiImpl.dataStore.GetNameTable().ListServiceName()
	return &trace_proxy_api.ListServiceNameResponse{
		Code:            trace_proxy_api.ListServiceNameResponse_CODE_OK,
		ServiceNameList: serviceNameList,
	}, nil
}

func (apiImpl *TraceProxyApiImpl) ListRootSpanName(ctx context.Context, req *trace_proxy_api.ListRootSpanNameRequest) (*trace_proxy_api.ListRootSpanNameResponse, error) {
	emptyList := []string{}

	cfg, err := config.LoadServerCfg(apiImpl.cfgPath)
	if err != nil {
		return nil, err
	}
	tokenInfo, err := apiImpl.getTokenInfo(cfg.LinkSaasAddr, req.Token)
	if err != nil {
		return &trace_proxy_api.ListRootSpanNameResponse{
			Code:             trace_proxy_api.ListRootSpanNameResponse_CODE_WRONG_TOKEN,
			ErrMsg:           "错误的访问令牌",
			RootSpanNameList: emptyList,
		}, nil
	}
	if !apiImpl.hasPerm(tokenInfo.ProjectId, cfg.ProjectList) {
		return &trace_proxy_api.ListRootSpanNameResponse{
			Code:             trace_proxy_api.ListRootSpanNameResponse_CODE_NO_PERMISSION,
			ErrMsg:           "没有权限",
			RootSpanNameList: emptyList,
		}, nil
	}

	rootSpanNameList := apiImpl.dataStore.GetNameTable().ListRootSpanName(req.FilterByServiceName, req.ServiceName)
	return &trace_proxy_api.ListRootSpanNameResponse{
		Code:             trace_proxy_api.ListRootSpanNameResponse_CODE_OK,
		RootSpanNameList: rootSpanNameList,
	}, nil
}

func (apiImpl *TraceProxyApiImpl) ListTrace(ctx context.Context, req *trace_proxy_api.ListTraceRequest) (*trace_proxy_api.ListTraceResponse, error) {
	emptyList := []*trace_proxy_api.TraceInfo{}

	cfg, err := config.LoadServerCfg(apiImpl.cfgPath)
	if err != nil {
		return nil, err
	}
	tokenInfo, err := apiImpl.getTokenInfo(cfg.LinkSaasAddr, req.Token)
	if err != nil {
		return &trace_proxy_api.ListTraceResponse{
			Code:      trace_proxy_api.ListTraceResponse_CODE_WRONG_TOKEN,
			ErrMsg:    "错误的访问令牌",
			TraceList: emptyList,
		}, nil
	}
	if !apiImpl.hasPerm(tokenInfo.ProjectId, cfg.ProjectList) {
		return &trace_proxy_api.ListTraceResponse{
			Code:      trace_proxy_api.ListTraceResponse_CODE_NO_PERMISSION,
			ErrMsg:    "没有权限",
			TraceList: emptyList,
		}, nil
	}

	traceItemList := apiImpl.dataStore.GetTraceTable().List()
	traceList := []*trace_proxy_api.TraceInfo{}
	for _, traceItem := range traceItemList {
		spanItem := apiImpl.dataStore.GetSpanTable().Get(traceItem.RootSpanId)
		if spanItem == nil {
			continue
		}
		if req.FilterByServiceName && spanItem.ServiceName != req.ServiceName {
			continue
		}
		if req.FilterByRootSpanName && spanItem.SpanName != req.RootSpanName {
			continue
		}
		if req.FilterByAttr {
			match := false
			spanItem.AttrMap.Range(func(k string, v pcommon.Value) bool {
				if k == req.Attr.Key && v.AsString() == req.Attr.Value {
					match = true
					return false
				}
				return true
			})
			if !match {
				continue
			}
		}
		traceList = append(traceList, traceItem.ToTraceInfo(spanItem.ToSpanInfo()))
	}
	//排序
	if req.SortBy == trace_proxy_api.SORT_BY_SORT_BY_START_TIME {
		sort.SliceStable(traceList, func(i, j int) bool {
			return !(traceList[i].RootSpan.StartTimeStamp < traceList[j].RootSpan.StartTimeStamp)
		})
	} else if req.SortBy == trace_proxy_api.SORT_BY_SORT_BY_CONSUME_TIME {
		sort.SliceStable(traceList, func(i, j int) bool {
			consumeI := traceList[i].RootSpan.EndTimeStamp - traceList[i].RootSpan.StartTimeStamp
			consumeJ := traceList[j].RootSpan.EndTimeStamp - traceList[j].RootSpan.StartTimeStamp

			return !(consumeI < consumeJ)
		})
	}

	if len(traceList) > int(req.Limit) {
		traceList = traceList[:int(req.Limit)]
	}

	return &trace_proxy_api.ListTraceResponse{
		Code:      trace_proxy_api.ListTraceResponse_CODE_OK,
		TraceList: traceList,
	}, nil
}

func (apiImpl *TraceProxyApiImpl) GetTrace(ctx context.Context, req *trace_proxy_api.GetTraceRequest) (*trace_proxy_api.GetTraceResponse, error) {
	emptyTrace := &trace_proxy_api.TraceInfo{}

	cfg, err := config.LoadServerCfg(apiImpl.cfgPath)
	if err != nil {
		return nil, err
	}
	tokenInfo, err := apiImpl.getTokenInfo(cfg.LinkSaasAddr, req.Token)
	if err != nil {
		return &trace_proxy_api.GetTraceResponse{
			Code:   trace_proxy_api.GetTraceResponse_CODE_WRONG_TOKEN,
			ErrMsg: "错误的访问令牌",
			Trace:  emptyTrace,
		}, nil
	}
	if !apiImpl.hasPerm(tokenInfo.ProjectId, cfg.ProjectList) {
		return &trace_proxy_api.GetTraceResponse{
			Code:   trace_proxy_api.GetTraceResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
			Trace:  emptyTrace,
		}, nil
	}

	traceItem, ok := apiImpl.dataStore.GetTraceTable().Get(req.TraceId)
	if !ok {
		return &trace_proxy_api.GetTraceResponse{
			Code:   trace_proxy_api.GetTraceResponse_CODE_NO_TRACE,
			ErrMsg: "追踪记录不存在",
			Trace:  emptyTrace,
		}, nil
	}
	if traceItem.RootSpanId == "" {
		return &trace_proxy_api.GetTraceResponse{
			Code:   trace_proxy_api.GetTraceResponse_CODE_NO_TRACE,
			ErrMsg: "追踪记录不存在",
			Trace:  emptyTrace,
		}, nil
	}
	rootSpanItem := apiImpl.dataStore.GetSpanTable().Get(traceItem.RootSpanId)
	if rootSpanItem == nil {
		return &trace_proxy_api.GetTraceResponse{
			Code:   trace_proxy_api.GetTraceResponse_CODE_NO_TRACE,
			ErrMsg: "追踪记录不存在",
			Trace:  emptyTrace,
		}, nil
	}
	return &trace_proxy_api.GetTraceResponse{
		Code:  trace_proxy_api.GetTraceResponse_CODE_OK,
		Trace: traceItem.ToTraceInfo(rootSpanItem.ToSpanInfo()),
	}, nil
}

func (apiImpl *TraceProxyApiImpl) ListSpan(ctx context.Context, req *trace_proxy_api.ListSpanRequest) (*trace_proxy_api.ListSpanResponse, error) {
	emptyList := []*trace_proxy_api.SpanInfo{}

	cfg, err := config.LoadServerCfg(apiImpl.cfgPath)
	if err != nil {
		return nil, err
	}
	tokenInfo, err := apiImpl.getTokenInfo(cfg.LinkSaasAddr, req.Token)
	if err != nil {
		return &trace_proxy_api.ListSpanResponse{
			Code:     trace_proxy_api.ListSpanResponse_CODE_WRONG_TOKEN,
			ErrMsg:   "错误的访问令牌",
			SpanList: emptyList,
		}, nil
	}
	if !apiImpl.hasPerm(tokenInfo.ProjectId, cfg.ProjectList) {
		return &trace_proxy_api.ListSpanResponse{
			Code:     trace_proxy_api.ListSpanResponse_CODE_NO_PERMISSION,
			ErrMsg:   "没有权限",
			SpanList: emptyList,
		}, nil
	}

	_, ok := apiImpl.dataStore.GetTraceTable().Get(req.TraceId)
	if !ok {
		return &trace_proxy_api.ListSpanResponse{
			Code:     trace_proxy_api.ListSpanResponse_CODE_NO_TRACE,
			ErrMsg:   "追踪记录不存在",
			SpanList: emptyList,
		}, nil
	}

	spanItemList := apiImpl.dataStore.GetSpanTable().ListByTrace(req.TraceId)
	spanList := []*trace_proxy_api.SpanInfo{}
	for _, spanItem := range spanItemList {
		spanList = append(spanList, spanItem.ToSpanInfo())
	}
	return &trace_proxy_api.ListSpanResponse{
		Code:     trace_proxy_api.ListSpanResponse_CODE_OK,
		SpanList: spanList,
	}, nil
}
